/**
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package models;

import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;

import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;

import play.data.validation.Email;
import play.data.validation.Password;
import play.data.validation.Required;
import play.db.jpa.Model;
import play.libs.Codec;
import play.libs.Mail;

/**
 * @author Ousama
 */
@Entity
public class IdeaDeveloper extends Model {
	/************* ATTRIBUTES !! ****************/
	@Required
	public String fullName;
	@Required
	public String username;
	@Password
	public String password;
	public String passwordHash;
	@Email
	public String eMail;
	@Required
	public String dateOfBirth;
	@Required
	public String address;
	public String theme;
	public int numberOfIdeasPosted;
	public int numberOfComments;
	public int mobileNumber;
	public int communityCounter;
	public Picture profilePicture;
	public boolean blocked;
	public boolean deactivated = false;
	@Required
	public String typeOfProfile; // can be either public "viewed by all"
									// or private "viewed by friends"
	/************* RELATIONS !! ***************/
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDeveloper1")
	public List<Organization> joinedOrg = new ArrayList<Organization>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDeveloper2")
	public List<Organization> blockedOrg = new ArrayList<Organization>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDeveloper3")
	public List<Organization> followedOrg = new ArrayList<Organization>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDeveloper4")
	public List<Entities> joinedEnt = new ArrayList<Entities>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDeveloper5")
	public List<Entities> blockedEnt = new ArrayList<Entities>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDeveloper6")
	public List<Entities> followedEnt = new ArrayList<Entities>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDeveloper7")
	public List<Topic> followedTop = new ArrayList<Topic>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDeveloper8")
	public List<Topic> joinedTop = new ArrayList<Topic>();
	@OneToMany(mappedBy = "creator", cascade = CascadeType.ALL)
	public List<Topic> createdTopics = new ArrayList<Topic>();
	@OneToMany(mappedBy = "creator", cascade = CascadeType.ALL)
	public List<Idea> createdIdeas = new ArrayList<Idea>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDeveloper9")
	public List<Idea> spamIdea = new ArrayList<Idea>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDeveloper12")
	public List<Idea> voteIdea = new ArrayList<Idea>();
	@OneToMany(mappedBy = "creator", cascade = CascadeType.ALL)
	public List<Comment> createdComments = new ArrayList<Comment>();
	@ManyToMany
	@JoinTable(name = "IdeaDeveloper10")
	public List<Comment> spamComment = new ArrayList<Comment>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDevelope15")
	public List<Tag> followedTag = new ArrayList<Tag>();
	@ManyToMany
	public List<ActionPlan> volunteer = new ArrayList<ActionPlan>();
	@ManyToMany
	public List<ActionItem> actionItem = new ArrayList<ActionItem>();
	@OneToMany(mappedBy = "dev", cascade = CascadeType.ALL)
	public List<Request> requests = new ArrayList<Request>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDeveloper11")
	public List<Topic> blockedTopic = new ArrayList<Topic>();
	@OneToMany(mappedBy = "notificationsViewer", cascade = CascadeType.ALL)
	public List<Notification> notifications = new ArrayList<Notification>();// the
																			// list
																			// of
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDevelope16")
	public List<Entities> unfollowedEnt = new ArrayList<Entities>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDevelope17")
	public List<Topic> unfollowedTop = new ArrayList<Topic>();
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDevelope18")
	public List<Organization> unfollowedOrg = new ArrayList<Organization>(); // notifications
	@ManyToMany(cascade = CascadeType.PERSIST)
	@JoinTable(name = "IdeaDevelope19")
	public List<Tag> unfollowedTag = new ArrayList<Tag>(); // an
	// has
	// (shereef)

	@OneToMany(mappedBy = "ideaDeveloper", cascade = CascadeType.ALL)
	public List<Rate> rates = new ArrayList<Rate>();

	@ManyToMany(cascade = CascadeType.PERSIST)
	public List<IdeaDeveloper> friends = new ArrayList<IdeaDeveloper>();

	/**
	 * Delete the IdeaDeveloper if possible.
	 */
	public void delete2() {

		// unfollowedEnt,unfollowedTop,unfollowedOrg,unfollowedTag

		// deleting the requests
		for (int i = 0; i < requests.size(); i++) {
			requests.get(i).delete2();
		}
		// not volunerting anymore
		for (int i = 0; i < actionItem.size(); i++) {
			actionItem.get(i).volunteers.remove(this);
			actionItem.get(i).save();
		}
		// deleteing the corrospendig organizers
		List<Organizer> orgz = Organizer.find("ideaDeveloper = ?", this)
				.fetch();
		for (int i = 0; i < orgz.size(); i++) {
			orgz.get(i).delete2();
		}

		// deleting the comments made by him
		for (int i = 0; i < createdComments.size(); i++) {
			createdComments.get(i).delete2();
		}
		// delete the volunteering task
		for (int i = 0; i < volunteer.size(); i++) {
			volunteer.get(i).volunteers.remove(this);
			volunteer.get(i).save();
		}
		// canceling the following
		for (int i = 0; i < followedTag.size(); i++) {
			followedTag.get(i).followed.remove(this);
			followedTag.get(i).save();
		}
		for (int i = 0; i < unfollowedTag.size(); i++) {
			unfollowedTag.get(i).unfollowed.remove(this);
			unfollowedTag.get(i).save();
		}
		// deleteing the spam comment by him
		for (int i = 0; i < spamComment.size(); i++) {
			spamComment.get(i).spam.remove(this);
			spamComment.get(i).save();
		}
		// deleteing the member relation between the developer and his
		// organizations
		for (int i = 0; i < joinedOrg.size(); i++) {
			joinedOrg.get(i).members.remove(this);
			joinedOrg.get(i).save();
		} // deleting the organizationLead associated with him
		List<OrganizationLead> leaders = OrganizationLead.find(
				"ideaDeveloper = ?", this).fetch();
		for (int i = 0; i < leaders.size(); i++) {
			leaders.get(i).delete2();
		}

		// delete the blocked instance
		for (int i = 0; i < blockedOrg.size(); i++) {
			blockedOrg.get(i).blocked.remove(this);
			blockedOrg.get(i).save();
		}

		// delete the follower instance
		for (int i = 0; i < followedOrg.size(); i++) {
			followedOrg.get(i).followed.remove(this);
			followedOrg.get(i).save();
		}
		for (int i = 0; i < unfollowedOrg.size(); i++) {
			unfollowedOrg.get(i).unfollowed.remove(this);
			unfollowedOrg.get(i).save();
		}

		// deleteing the member relation between the developer and his
		// Entanizations
		for (int i = 0; i < joinedEnt.size(); i++) {
			joinedEnt.get(i).members.remove(this);
			joinedEnt.get(i).save();
		}

		// delete the blocked instance
		for (int i = 0; i < blockedEnt.size(); i++) {
			blockedEnt.get(i).blocked.remove(this);
			blockedEnt.get(i).save();
		}

		// delete the follower instance
		for (int i = 0; i < followedEnt.size(); i++) {
			followedEnt.get(i).followed.remove(this);
			followedEnt.get(i).save();
		}
		for (int i = 0; i < unfollowedEnt.size(); i++) {
			unfollowedEnt.get(i).unfollowed.remove(this);
			unfollowedEnt.get(i).save();
		}

		// deleteing the current Topics
		for (int i = 0; i < createdTopics.size(); i++) {
			createdTopics.get(i).delete2();
		}

		// delets following topics and joined
		for (int i = 0; i < followedTop.size(); i++) {
			followedTop.get(i).followed.remove(this);
			followedTop.get(i).save();
		}
		for (int i = 0; i < unfollowedTop.size(); i++) {
			unfollowedTop.get(i).unfollowed.remove(this);
			unfollowedTop.get(i).save();
		}

		for (int i = 0; i < joinedTop.size(); i++) {
			joinedTop.get(i).joined.remove(this);
			joinedTop.get(i).save();
		}
		// deleteing the created Ideas
		for (int i = 0; i < createdIdeas.size(); i++) {
			createdIdeas.get(i).delete2();
		}

		// delete the spam done but him
		for (int i = 0; i < spamIdea.size(); i++) {
			spamIdea.get(i).spam.remove(this);
			spamIdea.get(i).save();
		}
		for (int i = 0; i < voteIdea.size(); i++) {
			voteIdea.get(i).vote.remove(this);
			voteIdea.get(i).save();
		}
		for (int i = 0; i < rates.size(); i++) {
			rates.get(i).delete2();// delete2 fel rate mosh mawgooda ..
		}

		for (int i = 0; i < friends.size(); i++) {
			friends.get(i).friends.remove(this);
			friends.get(i).save();
		}
		Log log = new Log("^ was deleted.");
		log.ids = this.id + "";
		log.types = "developer";
		log.save();
                // deleting acctually
		this.delete();
		
		

	}

	/**
	 * Empty Constructor
	 */
	public IdeaDeveloper() {
	}

	/**
	 * Constructor that takes some attributes
	 * 
	 * @param fullName
	 *            the full name of the idea developer
	 * @param username
	 *            the user name of the idea developer
	 * @param password
	 *            the password of the idea developer
	 * @param email
	 *            the email of the idea developer
	 * @param dateOfBirth
	 *            the date of birth of the idea developer
	 * @param address
	 *            the address of the idea developer
	 */
	public IdeaDeveloper(String fullName, String username, String password,
			String email, String dateOfBirth, String address) {
		this.fullName = fullName;
		this.username = username;
		this.password = password;
		this.eMail = email;
		this.passwordHash = Codec.hexMD5(password);
		this.dateOfBirth = dateOfBirth;
		this.address = address;
		this.theme = "";
		this.numberOfIdeasPosted = 0;
		this.numberOfComments = 0;
		this.mobileNumber = 0;
		this.communityCounter = 0;
		this.typeOfProfile = "public";
		// this.imagePath = new Blob();
		this.blocked = false;
		
		
	}

	/**
	 * This method can act as Add/Edit/Delete user information depending on the
	 * input as if the there was no address and a the new address was not an
	 * empty string it will add it,if the value was not an empty string and the
	 * string was an empty string it will delete the value, and if both are not
	 * empty strings it will edit the value inside.
	 * 
	 * @author KimO
	 * @param usernameOfWhoWillBeEdited
	 *            the user name of the idea developer or the user in general
	 *            whose data will be changed.
	 * 
	 * @param newAddress
	 *            the new address which will replace the user's old address.
	 * 
	 * @param newTheme
	 *            the new theme which will replace the user's old theme.
	 * 
	 * @param newImage
	 *            the new path for the user's profile picture.
	 * 
	 * @return "Done!" if the changed are done successfully , otherwise it
	 *         returns "Cannot Update!"
	 */
	public static String editUserInformation(String usernameOfWhoWillBeEdited,
			String usernameOfTheEditor, String newAddress, int mobileNumber,
			String eMail) {
		
		

		try {
			if (/* if he is the user himself */usernameOfTheEditor
					.equals(usernameOfWhoWillBeEdited)) {

				// get the user whose data will be edited
				IdeaDeveloper ideaDevelopertoBeEdited = (IdeaDeveloper) (IdeaDeveloper
						.find("username = ?", usernameOfWhoWillBeEdited)
						.fetch()).get(0);
				// setting the changed data
				ideaDevelopertoBeEdited.address = newAddress;
				ideaDevelopertoBeEdited.mobileNumber = mobileNumber;
				ideaDevelopertoBeEdited.eMail = eMail;
				// updating the database after changes are done
				ideaDevelopertoBeEdited.save();
				
				Log log = new Log("^ changed his information.");
				log.ids = ideaDevelopertoBeEdited.id + "";
				log.types = "developer";
				log.save();
				
				return "Done!";
			}
			return "Cannot Update!";
		} catch (Exception e) {
			return "Exception happened!";
		}
	}

	/**
	 * This method can act as Add/Edit/Delete user information using the method
	 * editUserInformation(String usernameOfWhoWillBeEdited, String newAddress,
	 * String newTheme, String newImagePath)
	 * 
	 * @author KimO
	 * @param ideaDeveloperWhoWillBeEdited
	 *            the idea developer or the user in general whose data will be
	 *            changed.
	 * 
	 * @param newAddress
	 *            the new address which will replace the user's old address.
	 * 
	 * @param newTheme
	 *            the new theme which will replace the user's old theme.
	 * 
	 * @param newImagePath
	 *            the new path for the user's profile picture.
	 * 
	 * @return "Done!" if the changed are done successfully , otherwise it
	 *         returns "Cannot Update!"
	 */
	// public static String editUserInformation(
	// IdeaDeveloper ideaDeveloperWhoWillBeEdited,
	// IdeaDeveloper ideaDeveloperWhoWillEdit, String newAddress,
	// String newTheme, String eMail, Picture newImagePath) {
	//
	// try {
	// return editUserInformation(ideaDeveloperWhoWillBeEdited.username,
	// ideaDeveloperWhoWillEdit.username, newAddress, newTheme,
	// eMail, newImagePath);
	// } catch (Exception e) {
	// return "Exception happened!";
	// }
	// }

	/**
	 * this method checks if an idea developer is an organization lead of a
	 * specific organization
	 * 
	 * @author KimO
	 * @param member
	 *            the idea developer who is checked
	 * @param organization
	 *            the organization which the method checks on
	 * @return true if he is, otherwise false
	 */
	public static boolean canLeadOrganization(IdeaDeveloper member,
			Organization organization) {
		try {
			OrganizationLead lead = OrganizationLead.find("ideaDeveloper = ?",
					member).first();

			if (organization.managers.contains(lead)) {
				return true;
			}
			if (organization.creator.equals(lead)) {
				return true;
			}
			return false;

		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * this method checks if an idea developer is an organizer on a specific
	 * entity
	 * 
	 * @author KimO
	 * @param member
	 *            the idea developer who is checked
	 * @param entity
	 *            the entity which the method checks on
	 * @return true if he is, otherwise false
	 */
	public static boolean canLeadEntity(IdeaDeveloper member, Entities entity) {

		try {
			if (canLeadOrganization(member, entity.liesIn))
				return true;

			Organizer organizer = Organizer.find("ideaDeveloper = ?", member)
					.first();

			boolean flag = true;
			do {
				if (entity.managers.contains(organizer))
					return true;
				if (entity.parent != null) {
					entity = entity.parent;
				} else {
					flag = false;
				}
			} while (flag);

			return false;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * this method checks if an idea developer is an organizer on a specific
	 * topic
	 * 
	 * @author KimO
	 * @param member
	 *            the idea developer who is checked
	 * @param topic
	 *            the topic which the method checks on
	 * @return true if he is, otherwise false
	 */
	public static boolean canLeadTopic(IdeaDeveloper member, Topic topic) {
		try {

			Organizer organizer = Organizer.find("ideaDeveloper = ?", member)
					.first();

			if (topic.managers.contains(organizer))
				return true;

			if (topic.topicOrg != null) {
				if (canLeadOrganization(member, topic.topicOrg))
					return true;
			}
			if (topic.topicEnt != null) {
				if (canLeadEntity(member, topic.topicEnt))
					return true;
			}
			if (topic.creator.equals(member))
				return true;
			return false;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * takes Idea developer and organization and and see if he is a member
	 * 
	 * @param member
	 *            Idea developer that will check if member in organization
	 * @param organization
	 *            organization that will check that idea developer is a member
	 *            in it
	 * @return true if he is a member
	 * @return false if he is not a member
	 */
	public static boolean isMemberOrganization(IdeaDeveloper member,
			Organization organization) {
		try {
			if (canLeadOrganization(member, organization))
				return true;

			if (member.blockedOrg.contains(organization))
				return false;

			if (organization.type.toLowerCase().equals("public"))
				return true;

			if (member.joinedOrg.contains(organization))
				return true;
			else
				return false;

		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * takes idea developer and organization and see if he can view it
	 * 
	 * can view if he not blocked and is a member or it's type is public
	 * 
	 * @param member
	 *            the viewer that want to see organization
	 * @param organization
	 *            organization that is being viewed
	 * @return true can view is not blocked and is member or organization is
	 *         public
	 * @return false can't view is blocked or not a member or organization is
	 *         secret
	 */
	public static boolean canViewOrganization(IdeaDeveloper member,
			Organization organization) {
		try {
			if (canLeadOrganization(member, organization))
				return true;

			if (member.blockedOrg.contains(organization))
				return false;

			if (!organization.type.equalsIgnoreCase("secret"))
				return true;
			else
				return member.joinedOrg.contains(organization);

		} catch (Exception e) {
			return false;
		}
	}

	public static boolean canViewOrganizationForOrganizationView(IdeaDeveloper member,
			Organization organization) {
		try {
			if (canLeadOrganization(member, organization))
				return true;

			if (member.blockedOrg.contains(organization))
				return false;

//			if (!organization.type.equalsIgnoreCase("secret"))
//				return true;
			else
				return member.joinedOrg.contains(organization);

		} catch (Exception e) {
			return false;
		}
	}
	
	/**
	 * takes idea developer and entity and see if member
	 * 
	 * @param member
	 *            member to be checked if in entity
	 * @param entit
	 *            entity to check is a member of
	 * @return true is a organization lead or organization is public or is a
	 *         member in entity and parent entities false is not a member in
	 *         entity or parent entities or blocked or organization is secret or
	 *         private and not a member
	 */
	public static boolean isMemberEntity(IdeaDeveloper member, Entities entit) {
		try {
			if (canLeadEntity(member, entit))
				return true;
			if (member.blockedEnt.contains(entit))
				return false;
			if (isMemberOrganization(member, entit.liesIn))
				return true;
			// private or secret
			if (member.blockedEnt.contains(entit))
				return false;
			if (member.joinedEnt.contains(entit))
				return true;

			while (entit.parent != null) {
				entit = entit.parent;
				if (member.blockedEnt.contains(entit))
					return false;
				if (member.joinedEnt.contains(entit))
					return true;
			}
			return false;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * takes idea developer and entity and see if he can view it he can view if
	 * he is not blocked from the organization of the entity and is a member in
	 * the entity or it is public
	 * 
	 * @param member
	 *            idea developer that wants to see entity
	 * @param entit
	 *            entity that is being viewed
	 * @return true if not blocked from parent organization and not blocked from
	 *         entity and is a member in entity or entity and organization are
	 *         public
	 * @return false if blocked from parent organization or is not a member in
	 *         entity or entity and organization are not public
	 */
	public static boolean canViewEntity(IdeaDeveloper member, Entities entit) {
		try {
			if (canLeadEntity(member, entit))
				return true;
			if (member.blockedEnt.contains(entit))
				return false;
			if (canViewOrganization(member, entit.liesIn))
				return true;
			// private or secret
			if (member.joinedEnt.contains(entit))
				return true;

			while (entit.parent != null) {
				entit = entit.parent;
				if (member.blockedEnt.contains(entit))
					return false;
				if (member.joinedEnt.contains(entit))
					return true;
			}
			return false;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * checks if a user is a member in this topic or it's entity or organization
	 * 
	 * @author KimO
	 * 
	 * @param viewer
	 *            the idea developer who we check if he is a member
	 * @param topicViewed
	 *            the topic we check on it
	 * @return boolean variable true if the idea developer is a member otherwise
	 *         it returns false
	 */
	public static boolean isMemberTopic(IdeaDeveloper viewer, Topic topicViewed) {
		try {
			if (canLeadTopic(viewer, topicViewed))
				return true;
			if (topicViewed.hidden) {
				if (topicViewed.joined.contains(viewer)) {
					return true;
				}
			} else {
				if (topicViewed.topicOrg != null) {
					if (isMemberOrganization(viewer, topicViewed.topicOrg))
						return true;
				} else {
					if (isMemberEntity(viewer, topicViewed.topicEnt))
						return true;
				}
			}

			if (viewer.joinedTop.contains(topicViewed))
				return true;

			return false;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * a method checking if an idea developer can view a topic or not and it
	 * returns a boolean variable
	 * 
	 * @author KimO
	 * 
	 * @param viewer
	 *            the idea developer who we check if he is a member
	 * @param topicViewed
	 *            the topic we check on it
	 * @return boolean variable true if the idea developer can check a certain
	 *         topic otherwise it returns false
	 */
	public static boolean canViewTopic(IdeaDeveloper viewer, Topic topicViewed) {
		if (topicViewed.published == true) {
			if (canLeadTopic(viewer, topicViewed))
				return true;

			if (topicViewed.hidden) {
				if (topicViewed.joined.contains(viewer)) {
					return true;
				}
			} else {
				if (topicViewed.topicOrg != null) {
					if (canViewOrganization(viewer, topicViewed.topicOrg))
						return true;
				} else {
					if (canViewEntity(viewer, topicViewed.topicEnt))
						return true;
				}
			}
			if (viewer.joinedTop.contains(topicViewed))
				return true;

			return false;
		}

		return false;

	}

	/**
	 * it checks if an idea developer can share a specific idea in a specific
	 * organization and it returns a boolean variable
	 * 
	 * @author KimO
	 * 
	 * @param organizationToBeChecked
	 *            the organization from where the idea will be shared
	 * @param ideaToBeShared
	 *            the idea which will be shared
	 * @param ideaDeveloperSharing
	 *            the idea developer sharing the idea
	 * @return if the idea developer can share the idea it returns true else it
	 *         returns false
	 */

	public static boolean canShareIdea(Organization organizationToBeChecked,
			Idea ideaToBeShared, IdeaDeveloper ideaDeveloperSharing) {
		try {
			return (isMemberOrganization(ideaDeveloperSharing,
					organizationToBeChecked));
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * this method checks if the idea developer can share and idea in his
	 * profile or not and it returns a boolean variable
	 * 
	 * @author KimO
	 * 
	 * @param ideaToBeShared
	 *            the idea which the method checks it can be shared or not
	 * @param ideaDeveloperSharing
	 *            the idea developer the method checks if he can share this idea
	 *            or not
	 * @return if the idea developer can share the idea it returns true else it
	 *         returns false
	 */
	public static boolean canShareIdeaToHisProfile(Idea ideaToBeShared,
			IdeaDeveloper ideaDeveloperSharing) {
		try {
			boolean flag = canViewIdea(ideaDeveloperSharing, ideaToBeShared);
			// if (flag) {
			// ideaDeveloperSharing.ideasShared.add(ideaToBeShared);
			// }
			return flag;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * checks to see if this idea being viewed parent topic or entity or
	 * organization can view them
	 * 
	 * @param viewer
	 *            ideaDeveloper
	 * @param ideaViewed
	 *            the idea that is being checked
	 * @return true if idea belongs to organization and the viewer an view
	 *         organization or belongs to entity and can view entity or topic
	 *         and can view topic
	 * @return false if not
	 */
	public static boolean canViewIdea(IdeaDeveloper viewer, Idea ideaViewed) {
		try {
			if (ideaViewed.published == true) {
				if (ideaViewed.ideaOrg != null) {
					return (canViewOrganization(viewer, ideaViewed.ideaOrg));
				}
				if (ideaViewed.ideaEnt != null) {
					return (canViewEntity(viewer, ideaViewed.ideaEnt));
				}
				if (ideaViewed.ideaTopic != null) {
					return (canViewTopic(viewer, ideaViewed.ideaTopic));
				}
				return false;
			} else {
				return false;
			}
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * checks if an idea developer can comment or is member in a specific idea
	 * 
	 * @author KimO
	 * @param viewer
	 *            ideaDeveloper who will be checked
	 * @param ideaViewed
	 *            the idea that is being checked
	 * @return true if he can , otherwise false
	 */
	public static boolean isMemberIdea(IdeaDeveloper viewer, Idea ideaViewed) {
		try {
			if (ideaViewed.ideaOrg != null) {

				return (isMemberOrganization(viewer, ideaViewed.ideaOrg));
			}
			if (ideaViewed.ideaEnt != null) {
				return (isMemberEntity(viewer, ideaViewed.ideaEnt));
			}
			if (ideaViewed.ideaTopic != null) {
				return (isMemberTopic(viewer, ideaViewed.ideaTopic));
			}
			return false;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * this methods invites a user to join the application
	 * 
	 * @author KimO
	 * 
	 * @param toEmail
	 *            the invitation receiver
	 * @param fullname
	 *            the invitor's full name
	 */
	public static void sendInvitationMail(String fullname, String toEmail) {
		try {
			SimpleEmail email = new SimpleEmail();
			email.setFrom("megasoft.noreply@gmail.com");
			email.addTo(toEmail);
			email.setSubject("Megasoft Company");
			email.setMsg("Hi, \n"
					+ fullname
					+ " has invited u to join megasoft application \nTo join click on the link below  \nhttp://localhost:9000/SignUp/SignUp");
			Mail.send(email);
		} catch (Exception e) {
		}
	}

	/**
	 * this method can be used to send an email to only one email
	 * 
	 * @author KimO
	 * @param toEmail
	 *            the email of the receiver
	 * @param subject
	 *            the subject of the email
	 * @param body
	 *            the body of the email
	 */
	public static void sendEMail(String toEmail, String subject, String body) {
		try {
			SimpleEmail email = new SimpleEmail();
			email.setFrom("megasoft.noreply@gmail.com");
			email.addTo(toEmail);
			email.setSubject(subject);
			email.setMsg(body);
			Mail.send(email);
		} catch (Exception e) {
		}
	}

	/**
	 * this method can be used to send an email to many emails
	 * 
	 * @author KimO
	 * @param toEmail
	 *            the email of the receiver
	 * @param subject
	 *            the subject of the email
	 * @param body
	 *            the body of the email
	 */
	public static void sendEMail(String[] toEmail, String subject, String body) {
		try {
			SimpleEmail email = new SimpleEmail();
			email.setFrom("megasoft.noreply@gmail.com");
			for (String toemail : toEmail) {
				email.addTo(toemail);
			}
			email.setSubject(subject);
			email.setMsg(body);
			Mail.send(email);
		} catch (Exception e) {
		}
	}

	/**
	 * allows the Idea Developer can create Organization and become its
	 * Organization lead by default
	 * 
	 * @author OmarKhaled
	 * @param lead
	 *            the user to be Organization Lead
	 * @param name
	 *            the name of the Organization being created
	 * @return Organization which was created
	 */
	public static Organization createOrganization(OrganizationLead lead,
			String name) {
		return Organization.create(lead, name);
	}

	// this method should be created
	public void notification(String reason) {
	}

	public String toString() {

		return this.username;
	}

	/**
	 * check if an IdeaDeveloper can view other IdeaDeveloper's Profile
	 * 
	 * @author OmarKhaled
	 * @param toBeViewed
	 *            the user who owns the profile
	 * @param viewer
	 *            the user wants to view the profile
	 * @return true to view profile , or false unable to view profile
	 */
	public static boolean canViewProfile(IdeaDeveloper viewer,
			IdeaDeveloper toBeViewed) {
		if (toBeViewed.typeOfProfile.equalsIgnoreCase("public")) {
			return true;
		} else {
			if (toBeViewed.friends.contains(viewer))
				return true;
		}
		return false;
	}

	/**
	 * This methods changes the password of the ideaDeveloper
	 * 
	 * @author Maryam
	 * @param newPassword
	 *            the password that the user wants to change to
	 * 
	 */
	public void changePassword(String newPassword) {
		password = newPassword;
		passwordHash = Codec.hexMD5(newPassword);
		this.save();
		
		Log log = new Log("^ changed his password.");
		log.ids = this.id + "";
		log.types = "developer";
		log.save();

	}

	/**
	 * increment the counter by specific amount of points
	 * 
	 * @author Sameha
	 * 
	 * @param points
	 *            an integer number that the counter will be incremented by it
	 */
	public void incrementCounter(int points) {
		this.communityCounter += points;
		this.save();
	}

	/**
	 * decrement the counter by specific amount of points
	 * 
	 * @author Sameha
	 * 
	 * @param points
	 *            an integer number that the counter will be decremented by it
	 */
	public void decrementCounter(int points) {
		this.communityCounter -= points;
		this.save();
	}

	/**
	 * a method that allows Ideadeveloper to volunteer on the actionItem action
	 * bye sending a justified request
	 * 
	 * @author Amr Gamal
	 * @param action
	 *            the actionItem that ideadeveloper volunteers to work on
	 * @param body
	 *            body of the request sent
	 * @return String represents whether the request was done or whether the
	 *         ideadeveloper had already volunteered on that item
	 */
	public String volunteerOnActionItem(ActionItem action, String body) {
		boolean found = false;
		for (int i = 0; i < this.requests.size(); i++) {
			if (this.requests.get(i).type.equals("JoinItemFromDevToActionItem")
					&& this.requests.get(i).item == action)
				found = true;
		}
		if (found) {
			return "IdeaDeveloper already volunteered on this actionItem";
		} else {
			Request.RequestMe(action, this, "JoinItemFromDevToActionItem", body);
			return "Request successfully done";
		}
	}

	/**
	 * this method is user to let an idea developer join an organization
	 * 
	 * @author KimO
	 * @param ideaDeveloper
	 *            the idea developer that will join the organization
	 * @param organization
	 *            the organization that will be joined
	 * @return true if the method succeeded, false if an exception happened or
	 *         he is already a member in the organization
	 */
	public static boolean joinOrganization(IdeaDeveloper ideaDeveloper,
			Organization organization) {
		if (organization.members.contains(ideaDeveloper))
			return false;

		organization.members.add(ideaDeveloper);
		organization.save();
		ideaDeveloper.joinedOrg.add(organization);
		ideaDeveloper.save();
		organization.noOfMembers++;
		
		Log log = new Log("^ joined ^.");
		log.ids = ideaDeveloper.id + "," + organization.id;
		log.types = "developer,organization";
		log.save();
		
		return true;
	}


	public static boolean joinEntity(IdeaDeveloper ideaDeveloper,
			Entities entity) {
		if (entity.members.contains(ideaDeveloper)) {
			return false;
		}
		entity.members.add(ideaDeveloper);
		entity.save();
		ideaDeveloper.joinedEnt.add(entity);
		ideaDeveloper.save();
		
		Log log = new Log("^ joined ^.");
		log.ids = ideaDeveloper.id + "," + entity.id;
		log.types = "developer,entity";
		log.save();
		
		return true;
	}


	/**
	 * a method checking if an idea developer can view an action plan or not and
	 * it returns a boolean variable
	 * 
	 * @author KimO
	 * 
	 * @param viewer
	 *            the idea developer who we check if he is a member
	 * @param actionPlan
	 *            the action plan we check on it
	 * @return boolean variable true if the action plan developer can check a
	 *         certain topic otherwise it returns false
	 */
	public static boolean canViewActionPlan(IdeaDeveloper viewer,
			ActionPlan actionPlan) {
		try {
			if (actionPlan.ideas != null) {
				for (int i = 0; i < actionPlan.ideas.size(); i++) {
					if (!canViewIdea(viewer, actionPlan.ideas.get(i)))
						return false;
				}
				return true;
			}
			return true;
		} catch (Exception e) {

			return false;

		}
	}
}
